﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Convert_DVR_MS_to_iTunes
{
    public class INIFile
    {
        public string m_iniFileName;

        public INIFile(string INIPath)
        {
            if (string.IsNullOrEmpty(INIPath))
            {
                throw new System.ArgumentNullException("iniFileName");
            }

            m_iniFileName = INIPath;
        }


        /// <summary>
        /// Returns Value from INI file.
        /// </summary>
        /// <param name="iniFileName">Full path to the INI file.</param>
        /// <param name="section">The section containing the key.</param>
        /// <param name="key">The value's Key.</param>
        /// <returns>The returned string, or null if none existed.</returns>
        public string GetValue(
          string section,
          string key)
        {

            //Check Args:
            if (string.IsNullOrEmpty(section))
            {
                throw new System.ArgumentNullException("section");
            }
            if (string.IsNullOrEmpty(key))
            {
                throw new System.ArgumentNullException("key");
            }

            StringBuilder buffer = new StringBuilder(256);
            string sDefault = "";

            //Get a single string value from the INI file:
            if (API.GetPrivateProfileString(
              section, key, sDefault,
              buffer, buffer.Capacity, m_iniFileName) != 0)
            {
                //We had a result, so return it:
                return buffer.ToString();
            }
            else
            {
                //No result -- return null:
                return null;
            }
        }


        /// <summary>
        /// Writes a string to an INI file.
        /// </summary>
        /// <param name="iniFileName">Full path to the INI file.</param>
        /// <param name="section">The section containing the key.</param>
        /// <param name="key">The value's key.</param>
        /// <param name="value">The value.</param>
        /// <returns>True if the write was successful.</returns>
        public bool SetValue(
          string section,
          string key,
          string value)
        {
            //Check Args:
            if (string.IsNullOrEmpty(section))
            {
                throw new System.ArgumentNullException("section");
            }
            if (string.IsNullOrEmpty(key))
            {
                throw new System.ArgumentNullException("key");
            }

            if (string.IsNullOrEmpty(value))
            {
                //Null's cause delete. 
                //so convert to string, and use DeleteValue
                //method for explicit deletes:
                value = string.Empty;
            }

            return API.WritePrivateProfileString(section, key,
              value, m_iniFileName);
        }


        /// <summary>
        /// Deletes the value.
        /// </summary>
        /// <param name="iniFileName">Name of the ini file.</param>
        /// <param name="section">The section.</param>
        /// <param name="key">The key.</param>
        /// <returns>True if the key was successfully deleted.</returns>
        public bool DeleteValue(
          string section,
          string key
          )
        {
            if (string.IsNullOrEmpty(section))
            {
                throw new System.ArgumentNullException("section");
            }

            //key, but no value = delete key:
            return API.WritePrivateProfileString(section, key, null, m_iniFileName);
        }


        /// <summary>
        /// Gets List of values from an INI section.
        /// </summary>
        /// <param name="iniFileName">Full path to the INI file.</param>
        /// <param name="section">The section containing the key.</param>
        /// <returns>An array of strings, or null.</returns>
        public bool GetSection(
          string section,
          out string[] results)
        {
            //Check Args:
            if (string.IsNullOrEmpty(section))
            {
                throw new System.ArgumentNullException("section");
            }
            List<string> items = new List<string>();
            byte[] buffer = new byte[32768];
            int bufLen = 0;
            bufLen = API.GetPrivateProfileSection(section, buffer,
              buffer.GetUpperBound(0), m_iniFileName);
            if (bufLen == 0)
            {
                results = null;
                return false;
            }
            else
            {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < bufLen; i++)
                {
                    if (buffer[i] != 0)
                    {
                        sb.Append((char)buffer[i]);
                    }
                    else
                    {
                        if (sb.Length > 0)
                        {
                            string[] parts = sb.ToString().Split('=');
                            items.Add(parts[1].Trim());
                            //reset sb:
                            sb = new StringBuilder();
                        }
                    }
                }
            }
            results = items.ToArray();
            return true;
        }


        /// <summary>
        /// Gets List of values from an INI section.
        /// </summary>
        /// <param name="iniFileName">Full path to the INI file.</param>
        /// <param name="section">The section containing the key.</param>
        /// <returns>An array of strings, or null.</returns>
        public bool GetSection(
          string section,
          out Dictionary<string, string> results)
        {
            //Check Args:
            if (string.IsNullOrEmpty(section))
            {
                throw new System.ArgumentNullException("section");
            }
            List<string> items = new List<string>();
            byte[] buffer = new byte[32768];
            int bufLen = 0;
            bufLen = API.GetPrivateProfileSection(section, buffer,
              buffer.GetUpperBound(0), m_iniFileName);
            if (bufLen == 0)
            {
                results = null;
                return false;
            }
            else
            {
                results = new Dictionary<string, string>();
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < bufLen; i++)
                {
                    if (buffer[i] != 0)
                    {
                        sb.Append((char)buffer[i]);
                    }
                    else
                    {
                        if (sb.Length > 0)
                        {
                            string[] parts = sb.ToString().Split('=');
                            results[parts[0].Trim()] = parts[1].Trim();
                            //reset sb:
                            sb = new StringBuilder();
                        }
                    }
                }
            }
            return true;
        }


        /// <summary>
        /// Writes a List to an INI Section 
        /// </summary>
        /// <param name="iniFileName">Full path to the INI file.</param>
        /// <param name="section">The section containing the key.</param>
        /// <param name="items"></param>
        /// <returns></returns>
        public bool SetSection(
          string section,
          string[] items)
        {
            //Check Args:
            if (string.IsNullOrEmpty(section))
            {
                throw new System.ArgumentNullException("section");
            }
            //byte[] b = new byte[32768];
            //int j = 0;
            int keyCounter = 0;

            StringBuilder sb = new StringBuilder();
            if (items == null)
            {
                //Delete the section:
                return API.WritePrivateProfileSection(section, null, m_iniFileName);
            }
            foreach (string item in items)
            {
                keyCounter++;
                sb.Append(keyCounter.ToString());
                sb.Append("=");
                sb.Append(item);
                sb.Append((char)0);//Line ending

                /*
              string key = counter.ToString() + "=";
              ASCIIEncoding.ASCII.GetBytes(key, 0, key.Length, b, j);
              j += key.Length;
              ASCIIEncoding.ASCII.GetBytes(item, 0, item.Length, b, j);
              j += item.Length;
              b[j] = 0;
              j += 1;
              */
            }
            //b[j] = 0;
            sb.Append((char)0);//second vbNullString
            return API.WritePrivateProfileSection(section, sb, m_iniFileName);
        }


        public bool SetSection(
          string section,
          Dictionary<string, string> dictionary)
        {
            //Check Args:
            if (string.IsNullOrEmpty(section))
            {
                throw new System.ArgumentNullException("section");
            }
            //byte[] b = new byte[32768];
            //int j = 0;
            //int keyCounter = 0;

            StringBuilder sb = new StringBuilder();
            if (dictionary != null)
            {
                //Delete the section:
                return API.WritePrivateProfileSection(section, null, m_iniFileName);
            }
            foreach (KeyValuePair<string, string> item in dictionary)
            {
                sb.Append(item.Key);
                sb.Append("=");
                sb.Append(item.Value);
                sb.Append((char)0);//Line ending
            }
            sb.Append((char)0);//second vbNullString
            return API.WritePrivateProfileSection(section, sb, m_iniFileName);
        }


        /// <summary>
        /// Explicitly deletes the section.
        /// </summary>
        /// <param name="iniFileName">Full path to the INI file.</param>
        /// <param name="section">The section to delete.</param>
        /// <returns></returns>
        public bool DeleteSection(
            string section)
        {
            //Check Args:
            if (string.IsNullOrEmpty(section))
            {
                throw new System.ArgumentNullException("section");
            }
            //byte[] b = null;
            //return API.WritePrivateProfileSection(section, b, m_iniFileName);

            //No key = delete section:
            return API.WritePrivateProfileString(section, null, null, m_iniFileName);
        }


        /// <summary>
        /// Get name of all sections in INI File.
        /// </summary>
        /// <param name="iniFileName">Full path to the INI file.</param>
        /// <returns>an array of strings or null if empty.</returns>
        public string[] GetSectionNames()
        {
            //Check Args:
            List<string> sections = new List<string>();
            byte[] buffer = new byte[32768];
            int bufLen = 0;
            bufLen = API.GetPrivateProfileSectionNames(
              buffer,
              buffer.GetUpperBound(0),
              m_iniFileName);
            if (bufLen == 0)
            {
                return null;
            }
            else
            {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < bufLen; i++)
                {
                    if (buffer[i] != 0)
                    {
                        sb.Append((char)buffer[i]);
                    }
                    else
                    {
                        if (sb.Length > 0)
                        {
                            sections.Add(sb.ToString());
                            sb = new StringBuilder();
                        }
                    }
                }
            }
            return sections.ToArray();
        }



        /// <summary>
        /// Protected API class:
        /// </summary>
        protected class API
        {
            /// <summary>
            /// Wrapper for API Call 
            /// </summary>
            [DllImport("KERNEL32.DLL",
               EntryPoint = "GetPrivateProfileString")]
            public static extern int
              GetPrivateProfileString(string lpAppName,
              string lpKeyName, string lpDefault,
              StringBuilder lpReturnedString, int nSize,
              string lpFileName);

            /// <summary>
            /// Wrapper for API Call 
            /// </summary>
            [DllImport("KERNEL32.DLL")]
            public static extern int
              GetPrivateProfileInt(string lpAppName,
              string lpKeyName, int iDefault,
              string lpFileName);

            /// <summary>
            /// Wrapper for API Call 
            /// </summary>
            [DllImport("KERNEL32.DLL",
               EntryPoint = "WritePrivateProfileString")]
            public static extern bool
              WritePrivateProfileString(string lpAppName,
              string lpKeyName, string lpString,
              string lpFileName);

            /// <summary>
            /// Wrapper for API Call 
            /// </summary>
            [DllImport("KERNEL32.DLL",
               EntryPoint = "GetPrivateProfileSection")]
            public static extern int
              GetPrivateProfileSection(string lpAppName,
              byte[] lpReturnedString, int nSize,
              string lpFileName);

            /// <summary>
            /// Wrapper for API Call 
            /// </summary>
            [DllImport("KERNEL32.DLL",
               EntryPoint = "WritePrivateProfileSection")]
            public static extern bool
              WritePrivateProfileSection(string lpAppName,
              StringBuilder data, string lpFileName);

            /// <summary>
            /// Wrapper for API Call 
            /// </summary>
            [DllImport("KERNEL32.DLL",
               EntryPoint = "GetPrivateProfileSectionNames")]
            public static extern int
              GetPrivateProfileSectionNames(
              byte[] lpReturnedString,
              int nSize, string lpFileName);
        }
    }
}
